package com.eonmind.ai.service.impl;

import cn.hutool.json.JSONUtil;
import com.eonmind.ai.config.AiConfig;
import com.eonmind.ai.converts.AiDrawConvert;
import com.eonmind.ai.core.draw.model.AiDrawTaskModel;
import com.eonmind.ai.core.draw.model.AiDrawTaskResModel;
import com.eonmind.ai.core.draw.platform.mdJounery.MdDrawService;
import com.eonmind.ai.core.draw.platform.mdJounery.model.MdCommandRequest;
import com.eonmind.ai.core.draw.platform.mdJounery.model.MdTaskQueryResponse;
import com.eonmind.ai.dto.AiDrawDto;
import com.eonmind.ai.mapper.AiDrawMapper;
import com.eonmind.ai.service.IAiDrawService;
import com.eonmind.common.contract.application.redis.service.RedisService;
import com.eonmind.common.contract.data.response.PageResponse;
import com.eonmind.common.contract.data.response.ResponseEntity;
import com.eonmind.common.contract.enums.DelEnum;
import com.eonmind.common.contract.enums.ai.AiArtworkStatusEnum;
import com.eonmind.common.contract.enums.ai.AiDrwaPlatformTypeEnum;
import com.eonmind.common.contract.enums.user.NoticeTypesEnum;
import com.eonmind.common.contract.enums.vip.ConsumptionTypeEnum;
import com.eonmind.common.contract.exception.BusinessException;
import com.eonmind.common.provider.dto.VipDto;
import com.eonmind.common.provider.entity.ai.AiArtwork;
import com.eonmind.common.provider.entity.ai.AiDrawPlatform;
import com.eonmind.user.contract.api.UserNoticeFeignService;
import com.eonmind.user.contract.dto.UserInfoData;
import com.eonmind.user.contract.dto.UserNoticeDto;
import com.eonmind.vip.contract.api.VipToAIFeignService;
import com.mongoplus.model.PageResult;
import com.mongoplus.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.eonmind.common.contract.enums.ErrorCode.PARAMS_ERROR;

@Slf4j
@Service
public class AiDrawService extends ServiceImpl<AiArtwork> implements IAiDrawService {
    @Resource
    private MdDrawService mdDrawService;
    @Resource
    private AiDrawMapper aiDrawMapper;

    @Resource
    private AiDrawPlatformService aiDrawPlatformService;

    @Resource
    private RedisService redisService;
    @Autowired
    private UserNoticeFeignService userNoticeFeignService;
    @Resource
    private AiConfig aiConfig;
    @Autowired
    private VipToAIFeignService vipToAIFeignService;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public MdTaskQueryResponse submitMjTask(UserInfoData userInfoData, AiDrawDto.AiDrawMjTaskRequest aiDrawTaskRequest) {
        isHasExecutingTask(userInfoData);
        // 扣减积分
        VipDto.VipBackToAiIsAcResponse vipBackToAiIsAcResponse = decUserCost(userInfoData);
        if (!vipBackToAiIsAcResponse.getIsAccess()) {
            throw new BusinessException(vipBackToAiIsAcResponse.getDesc());
        }

        // 构建prompt
        String prompt = aiDrawTaskRequest.getPrompt() + " --ar " + aiDrawTaskRequest.getRatio();
        AiDrawTaskResModel taskResModel = null;
        try {
            taskResModel = mdDrawService.submitDrawTask(buildMdDrawTaskModel(prompt, aiDrawTaskRequest));
        } catch (Exception e) {
            log.error("提交绘画任务异常：{}", e.getMessage(), e);
        } finally {
            sendSubmitNotice(userInfoData);

        }
        AiArtwork aiArtwork = new AiArtwork();
        aiArtwork.setUserId(userInfoData.getId());
        aiArtwork.setPlatformType(AiDrwaPlatformTypeEnum.MJ.getCode());
        aiArtwork.setPrompt(aiDrawTaskRequest.getPrompt());
        aiArtwork.setRatio(aiDrawTaskRequest.getRatio());
        MdTaskQueryResponse mdTaskQueryResponse = new MdTaskQueryResponse();
        // 任务提交失败，设置状态为待提交
        if (ObjectUtils.isEmpty(taskResModel)) {
            aiArtwork.setStatus(AiArtworkStatusEnum.WAIT_SUBMIT.getCode());
            mdTaskQueryResponse.setStatus(AiArtworkStatusEnum.WAIT_SUBMIT.name());
            aiDrawMapper.save(aiArtwork);
            return mdTaskQueryResponse;
        } else {
            // 构建任务保存到数据库
            aiArtwork.setTaskId(taskResModel.getTaskId());
            AiDrawPlatform aiDrawPlatformEntity = aiDrawPlatformService.selectById(taskResModel.getPlatformId());
            aiArtwork.setPlatformId(taskResModel.getPlatformId());
            aiDrawMapper.save(aiArtwork);
            // 查询绘画任务
            AiDrawPlatform aiDrawPlatform = aiDrawPlatformService.selectById(taskResModel.getPlatformId());
            mdTaskQueryResponse = mdDrawService.queryDrawTask(aiDrawPlatform, taskResModel.getTaskId());
            mdTaskQueryResponse.setTaskId(aiArtwork.getId());
            return mdTaskQueryResponse;
        }


    }

    private VipDto.VipBackToAiIsAcResponse decUserCost(UserInfoData userInfoData) {
        VipDto.VipAiServerDesc vipAiServerDesc = buildMjConsume(userInfoData);
        ResponseEntity<VipDto.VipBackToAiIsAcResponse> responseResponseEntity = vipToAIFeignService.aiServerIsAc(vipAiServerDesc);
        log.info("用户绘画任务提交，扣减积分：{},{}", vipAiServerDesc.toString(), responseResponseEntity.toString());
        return responseResponseEntity.getData();
    }

    private static VipDto.VipAiServerDesc buildMjConsume(UserInfoData userInfoData) {
        VipDto.VipAiServerDesc vipAiServerDesc = new VipDto.VipAiServerDesc().setCost(AiDrwaPlatformTypeEnum.MJ.getCost())
                .setType(ConsumptionTypeEnum.AI_DRAW.getCode())
                .setUserId(userInfoData.getId())
                .setModelId(Long.valueOf(AiDrwaPlatformTypeEnum.MJ.getCode()))
                .setModelName(AiDrwaPlatformTypeEnum.MJ.getDesc());
        return vipAiServerDesc;
    }

    private void sendSubmitNotice(UserInfoData userInfoData) {
        UserNoticeDto.UserSendNoticeRequest userSendNoticeRequest = new UserNoticeDto.UserSendNoticeRequest();
        userSendNoticeRequest.setUserId(userInfoData.getId());
        userSendNoticeRequest.setNoticeType(NoticeTypesEnum.SYSTEM_NOTICE);
        userSendNoticeRequest.setNoticeTitle("绘画任务提交成功");
        userSendNoticeRequest.setNoticeContent("您的绘画任务提交成功，请耐心等待结果，本次消耗：" + AiDrwaPlatformTypeEnum.MJ.getCost());
        ResponseEntity<Void> voidResponseEntity = userNoticeFeignService.sendUserNotice(userSendNoticeRequest);
        log.info("用户发送通知：{}", JSONUtil.toJsonStr(voidResponseEntity));
    }

    private void isHasExecutingTask(UserInfoData userInfoData) {
        List<AiArtwork> aiArtworkList = aiDrawMapper.selectUserWaitTask(userInfoData.getId());
        if (aiArtworkList.size() >= aiConfig.getMaxDrawTaskCount()) {
            throw new BusinessException("用户当前任务队列已满，请稍等再提交任务");
        }
    }

    @Override
    public AiDrawDto.MjDrawTaskQueryResponse queryMjTask(UserInfoData userInfoData, AiDrawDto.AiDrawTaskQueryRequest aiDrawTaskQueryRequest) {
        // 查询具体的任务
        AiArtwork aiArtwork = aiDrawMapper.selectById(aiDrawTaskQueryRequest.getId());

        if (ObjectUtils.isEmpty(aiArtwork) || !aiArtwork.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        // 先从redis获取
        String redisCacheProgress = redisService.get(String.valueOf(aiArtwork.getId()));
        if (redisCacheProgress != null && JSONUtil.isTypeJSON(redisCacheProgress)) {
            return JSONUtil.toBean(redisCacheProgress, AiDrawDto.MjDrawTaskQueryResponse.class);
        }
        AiDrawDto.MjDrawTaskQueryResponse taskQueryResponse = AiDrawConvert.toMjDrawTaskQueryResponse(aiArtwork);


        // 缓存到redis
        redisService.setnx(String.valueOf(aiArtwork.getId()), JSONUtil.toJsonStr(taskQueryResponse), 5L);
        // 查询进度
        return taskQueryResponse;
    }

    @Override
    public PageResponse<AiDrawDto.MjDrawTaskQueryResponse> pageMjDraw(UserInfoData userInfoData, AiDrawDto.AiDrawPageRequest aiDrawPageRequest) {
        PageResult<AiArtwork> pageResult = aiDrawMapper.pageDraw(userInfoData, aiDrawPageRequest, AiDrwaPlatformTypeEnum.MJ.getCode());
        PageResponse<AiDrawDto.MjDrawTaskQueryResponse> pageResponse = new PageResponse<>();
        pageResponse.setValue(aiDrawPageRequest.getPage(), pageResult.getTotalSize(), AiDrawConvert.toMjDrawTaskQueryResponseList(pageResult.getContentData()));
        return pageResponse;
    }

    @Override
    public void delDrawTask(UserInfoData userInfoData, AiDrawDto.DrawTaskDelRequest drawTaskDelRequest) {
        AiArtwork aiArtwork = aiDrawMapper.selectById(drawTaskDelRequest.getId());
        if (ObjectUtils.isEmpty(aiArtwork) || !aiArtwork.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        aiArtwork.setDel(DelEnum.DEL.getCode());
        aiDrawMapper.updateById(aiArtwork);
    }

    @Override
    public MdTaskQueryResponse executeMjCommandTask(UserInfoData userInfoData, AiDrawDto.AiDrawMjCommandRequest aiDrawMjCommandRequest) {
        isHasExecutingTask(userInfoData);
        // 扣减积分
        VipDto.VipBackToAiIsAcResponse vipBackToAiIsAcResponse = decUserCost(userInfoData);
        if (!vipBackToAiIsAcResponse.getIsAccess()) {
            throw new BusinessException(vipBackToAiIsAcResponse.getDesc());
        }
        
        Long id = aiDrawMjCommandRequest.getId();
        if (ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(aiDrawMjCommandRequest.getCustomId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        AiArtwork aiArtwork = aiDrawMapper.selectById(id);
        if (ObjectUtils.isEmpty(aiArtwork)) {
            throw new BusinessException(PARAMS_ERROR);
        }
        if (!aiArtwork.getUserId().equals(userInfoData.getId())) {
            throw new BusinessException(PARAMS_ERROR);
        }
        if (!AiArtworkStatusEnum.GENERATED_SUCCESSFULLY.getCode().equals(aiArtwork.getStatus())) {
            throw new BusinessException("当前任务状态不允许执行命令操作");
        }
        MdCommandRequest mdCommandRequest = new MdCommandRequest();
        mdCommandRequest.setTaskId(aiArtwork.getTaskId());
        mdCommandRequest.setCustomId(aiDrawMjCommandRequest.getCustomId());

        AiArtwork newAiArtwork = new AiArtwork();
        newAiArtwork.setPlatformType(AiDrwaPlatformTypeEnum.MJ.getCode());
        newAiArtwork.setPlatformId(aiArtwork.getPlatformId());
        newAiArtwork.setPrompt("Enlarge_" + aiArtwork.getTaskId() + "_" + aiDrawMjCommandRequest.getCustomId());
        newAiArtwork.setUserId(aiArtwork.getUserId());
        AiDrawTaskResModel aiDrawTaskResModel = null;
        MdTaskQueryResponse mdTaskQueryResponse = null;
        try {
            aiDrawTaskResModel = mdDrawService.executeCommandTask(mdCommandRequest);
            newAiArtwork.setTaskId(aiDrawTaskResModel.getTaskId());
            newAiArtwork.setPlatformId(aiDrawTaskResModel.getPlatformId());
            mdTaskQueryResponse = mdDrawService.queryDrawTask(aiDrawPlatformService.selectById(aiArtwork.getPlatformId()), aiDrawTaskResModel.getTaskId());

        } catch (Exception e) {
            log.error("Mj执行命令操作提交失败，进入待提交状态：{}", e.getMessage(), e);
            newAiArtwork.setStatus(AiArtworkStatusEnum.WAIT_SUBMIT.getCode());
            mdTaskQueryResponse = new MdTaskQueryResponse();
            mdTaskQueryResponse.setState(AiArtworkStatusEnum.WAIT_SUBMIT.name());

        } finally {
            sendSubmitNotice(userInfoData);
        }
        aiDrawMapper.save(newAiArtwork);
        return mdTaskQueryResponse;
    }

    @Override
    public void syncMjTaskProgress(UserInfoData userInfoData, AiDrawDto.AiDrawMjTaskSyncRequest taskSyncRequest) {
        if (ObjectUtils.isEmpty(userInfoData) || ObjectUtils.isEmpty(taskSyncRequest)) {
            throw new BusinessException("参数异常");
        }
        Long id = taskSyncRequest.getId();
        AiArtwork aiArtwork = aiDrawMapper.selectById(id);
        if (ObjectUtils.compare(aiArtwork.getUserId(), userInfoData.getId()) != 0) {
            throw new BusinessException("权限异常");
        }
        Long platformId = aiArtwork.getPlatformId();
        AiDrawPlatform aiDrawPlatform = aiDrawPlatformService.selectById(platformId);
        mdDrawService.syncMjTaskProgress(aiArtwork, aiDrawPlatform);
    }


    public AiDrawTaskModel buildMdDrawTaskModel(String prompt, AiDrawDto.AiDrawMjTaskRequest aiDrawTaskRequest) {
        AiDrawTaskModel aiDrawTaskModel = new AiDrawTaskModel();
        aiDrawTaskModel.setPrompt(prompt);
        aiDrawTaskModel.setBase64Array(aiDrawTaskRequest.getBase64Array());
        return aiDrawTaskModel;
    }
}
